<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  
  <title>RPC系列八之Thrift TServer源码分析 | Hexo</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta name="description" content="简介　　作为一个高性能RPC框架，还需要一个Server层，用于从Transport接收序列化的消息，再根据protocol反序列化并调用用户定义的消息处理器，然后序列化消息处理器的响应，最后再将它们写回Transport。Thrift模块化的结构使得它能提供各种Server实现。下面列出了Java中可用的TServer实现：　　1. TSimpleServer：它接受一个连接，处理连接请求，直到">
<meta property="og:type" content="article">
<meta property="og:title" content="RPC系列八之Thrift TServer源码分析">
<meta property="og:url" content="http://yoursite.com/2015/12/01/rpc/8.RPC系列之Thrift TServer源码分析/index.html">
<meta property="og:site_name" content="Hexo">
<meta property="og:description" content="简介　　作为一个高性能RPC框架，还需要一个Server层，用于从Transport接收序列化的消息，再根据protocol反序列化并调用用户定义的消息处理器，然后序列化消息处理器的响应，最后再将它们写回Transport。Thrift模块化的结构使得它能提供各种Server实现。下面列出了Java中可用的TServer实现：　　1. TSimpleServer：它接受一个连接，处理连接请求，直到">
<meta property="og:updated_time" content="2016-01-29T17:47:36.000Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="RPC系列八之Thrift TServer源码分析">
<meta name="twitter:description" content="简介　　作为一个高性能RPC框架，还需要一个Server层，用于从Transport接收序列化的消息，再根据protocol反序列化并调用用户定义的消息处理器，然后序列化消息处理器的响应，最后再将它们写回Transport。Thrift模块化的结构使得它能提供各种Server实现。下面列出了Java中可用的TServer实现：　　1. TSimpleServer：它接受一个连接，处理连接请求，直到">
  
    <link rel="alternative" href="/atom.xml" title="Hexo" type="application/atom+xml">
  
  
    <link rel="icon" href="/favicon.png">
  
  <link href="//fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet" type="text/css">
  <link rel="stylesheet" href="/css/style.css" type="text/css">
  

</head>
<body>
  <div id="container">
    <div id="wrap">
      <header id="header">
  <div id="banner"></div>
  <div id="header-outer" class="outer">
    <div id="header-title" class="inner">
      <h1 id="logo-wrap">
        <a href="/" id="logo">Hexo</a>
      </h1>
      
    </div>
    <div id="header-inner" class="inner">
      <nav id="main-nav">
        <a id="main-nav-toggle" class="nav-icon"></a>
        
          <a class="main-nav-link" href="/">Home</a>
        
          <a class="main-nav-link" href="/archives">Archives</a>
        
      </nav>
      <nav id="sub-nav">
        
          <a id="nav-rss-link" class="nav-icon" href="/atom.xml" title="RSS Feed"></a>
        
        <a id="nav-search-btn" class="nav-icon" title="Search"></a>
      </nav>
      <div id="search-form-wrap">
        <form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" results="0" class="search-form-input" placeholder="Search"><button type="submit" class="search-form-submit">&#xF002;</button><input type="hidden" name="sitesearch" value="http://yoursite.com"></form>
      </div>
    </div>
  </div>
</header>
      <div class="outer">
        <section id="main"><article id="post-rpc/8.RPC系列之Thrift TServer源码分析" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2015/12/01/rpc/8.RPC系列之Thrift TServer源码分析/" class="article-date">
  <time datetime="2015-12-01T00:00:00.000Z" itemprop="datePublished">2015-12-01</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/rpc/">rpc</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 class="article-title" itemprop="name">
      RPC系列八之Thrift TServer源码分析
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="u7B80_u4ECB"><a href="#u7B80_u4ECB" class="headerlink" title="简介"></a>简介</h2><p>　　作为一个高性能RPC框架，还需要一个Server层，用于从Transport接收序列化的消息，再根据protocol反序列化并调用用户定义的消息处理器，然后序列化消息处理器的响应，最后再将它们写回Transport。Thrift模块化的结构使得它能提供各种Server实现。下面列出了Java中可用的TServer实现：<br>　　1. <strong>TSimpleServer</strong>：它接受一个连接，处理连接请求，直到客户端关闭了连接，它才会去接受一个新的连接。正因为它只在一个单独的线程中以阻塞I/O的方式完成这些工作，所以它只能服务一个客户端连接，其他所有客户端在被服务器端接受之前都只能等待。TSimpleServer主要用于测试目的，不要在生产环境中使用它！<br>　　2. <strong>TNonblockingServer</strong>：使用NIO解决了TSimpleServer一个客户端阻塞其他所有客户端的问题。它通过使用java.nio.channels.Selector的select()方法，使得你阻塞在多个连接上，而不是阻塞在单一的连接上。当一或多个连接准备好被接受/读/写时，select()调用便会返回。TNonblockingServer处理这些连接的时候，要么接受它，要么从它那读数据，要么把数据写到它那里，然后再次调用select()来等待下一个可用的连接。通用这种方式，server可同时服务多个客户端。但是这样有一个问题：<strong>所有消息是被调用select()方法的同一个线程处理的（循环调用SelectionKey集合，按顺序逐一处理每一个消息）</strong>。假设有10个客户端，处理每条消息所需时间为100毫秒，那么，latency和吞吐量分别是多少？当一条消息被处理的时候，其他9个客户端就等着被select，所以客户端需要等待1秒钟才能从服务器端得到回应，吞吐量就是10个请求/秒。简单点就是：<strong>一个线程处理所有的io和业务代码执行</strong><br>　　3. <strong>THsHaServer</strong>：为了解决TNonblockingServer的问题（一个时间只能处理一条消息），THsHaServer（半同步/半异步的server）就应运而生了。它使用<strong>一个单独的线程来处理网络I/O，一个独立的worker线程池来处理消息</strong>。这样，只要有空闲的worker线程，消息就会被立即处理，因此多条消息能被并行处理。用上面的例子来说，现在的latency就是100毫秒，而吞吐量就是100个请求/秒（按10个客户端计算）。<br>　　4. <strong>TThreadedSelectorServer</strong>：它与THsHaServer的主要区别在于，TThreadedSelectorServer允许你用多个线程来处理网络I/O。它维护了<strong>两个线程池，一个用来处理网络I/O，另一个用来进行请求的处理</strong>。当网络I/O是瓶颈的时候，TThreadedSelectorServer比THsHaServer的表现要好。<br>　　5. <strong>TThreadPoolServer</strong>：有一个专用的线程用来接受连接，一旦接受了一个连接，它就会被放入ThreadPoolExecutor中的一个worker线程里处理io读写和业务代码执行，worker线程被绑定到特定的客户端连接上，直到它关闭。这意味着，如果有1万个并发的客户端连接，你就需要运行1万个线程。所以它对系统资源的消耗不像其他类型的server一样那么友好。此外，如果客户端数量超过了线程池中的最大线程数，在有一个worker线程可用之前，请求将被一直阻塞在那里。<br>　　下面我将逐一进入各个类，理解其实现原理，印证上面每个类的分析结果。</p>
<h2 id="TServer"><a href="#TServer" class="headerlink" title="TServer"></a>TServer</h2><p>　　首先我们看看TServer抽象类，其定义了Server的标准接口。同时，其静态内部类Args和AbstractServerArgs可以理解为java中构造者模式（Builder）的一种使用，这里不做过多的介绍！<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">TServer</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Args</span> <span class="keyword">extends</span> <span class="title">AbstractServerArgs</span>&lt;<span class="title">Args</span>&gt; </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">Args</span><span class="params">(TServerTransport transport)</span> </span>&#123;</span><br><span class="line">      <span class="keyword">super</span>(transport);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">AbstractServerArgs</span>&lt;<span class="title">T</span> <span class="keyword">extends</span> <span class="title">AbstractServerArgs</span>&lt;<span class="title">T</span>&gt;&gt; </span>&#123;</span><br><span class="line">    <span class="keyword">final</span> TServerTransport serverTransport;</span><br><span class="line">    TProcessorFactory processorFactory;</span><br><span class="line">    TTransportFactory inputTransportFactory = <span class="keyword">new</span> TTransportFactory();</span><br><span class="line">    TTransportFactory outputTransportFactory = <span class="keyword">new</span> TTransportFactory();</span><br><span class="line">    TProtocolFactory inputProtocolFactory = <span class="keyword">new</span> TBinaryProtocol.Factory();</span><br><span class="line">    TProtocolFactory outputProtocolFactory = <span class="keyword">new</span> TBinaryProtocol.Factory();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">AbstractServerArgs</span><span class="params">(TServerTransport transport)</span> </span>&#123;</span><br><span class="line">      serverTransport = transport;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> T <span class="title">processorFactory</span><span class="params">(TProcessorFactory factory)</span> </span>&#123;</span><br><span class="line">      <span class="keyword">this</span>.processorFactory = factory;</span><br><span class="line">      <span class="keyword">return</span> (T) <span class="keyword">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> T <span class="title">processor</span><span class="params">(TProcessor processor)</span> </span>&#123;</span><br><span class="line">      <span class="keyword">this</span>.processorFactory = <span class="keyword">new</span> TProcessorFactory(processor);</span><br><span class="line">      <span class="keyword">return</span> (T) <span class="keyword">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> T <span class="title">transportFactory</span><span class="params">(TTransportFactory factory)</span> </span>&#123;</span><br><span class="line">      <span class="keyword">this</span>.inputTransportFactory = factory;</span><br><span class="line">      <span class="keyword">this</span>.outputTransportFactory = factory;</span><br><span class="line">      <span class="keyword">return</span> (T) <span class="keyword">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//初始化各种factory</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">protected</span> TProcessorFactory processorFactory_;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">protected</span> TServerTransport serverTransport_;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">protected</span> TTransportFactory inputTransportFactory_;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">protected</span> TTransportFactory outputTransportFactory_;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">protected</span> TProtocolFactory inputProtocolFactory_;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">protected</span> TProtocolFactory outputProtocolFactory_;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">boolean</span> isServing;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">protected</span> TServerEventHandler eventHandler_;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">protected</span> <span class="keyword">volatile</span> <span class="keyword">boolean</span> stopped_ = <span class="keyword">false</span>;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> <span class="title">TServer</span><span class="params">(AbstractServerArgs args)</span> </span>&#123;</span><br><span class="line">    processorFactory_ = args.processorFactory;</span><br><span class="line">    serverTransport_ = args.serverTransport;</span><br><span class="line">    inputTransportFactory_ = args.inputTransportFactory;</span><br><span class="line">    outputTransportFactory_ = args.outputTransportFactory;</span><br><span class="line">    inputProtocolFactory_ = args.inputProtocolFactory;</span><br><span class="line">    outputProtocolFactory_ = args.outputProtocolFactory;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title">serve</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">//省略其他方法</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　我们可以看到，其成员变量serverTransport_、inputTransportFactory_、outputTransportFactory_、inputProtocolFactory_和outputProtocolFactory_等。这说明了TServer就是一个大管理，负责协调thrift的各个组件的正常工作，其最重要的一个方法便是抽象方法：serve。下面我们进入TSimpleServer看看其实现</p>
<h2 id="TSimpleServer"><a href="#TSimpleServer" class="headerlink" title="TSimpleServer"></a>TSimpleServer</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TSimpleServer</span> <span class="keyword">extends</span> <span class="title">TServer</span> </span>&#123;</span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">serve</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="comment">//省略部分代码</span></span><br><span class="line">	......</span><br><span class="line">    <span class="keyword">while</span> (!stopped_) &#123;</span><br><span class="line">      TTransport client = <span class="keyword">null</span>;</span><br><span class="line">      TProcessor processor = <span class="keyword">null</span>;</span><br><span class="line">      TTransport inputTransport = <span class="keyword">null</span>;</span><br><span class="line">      TTransport outputTransport = <span class="keyword">null</span>;</span><br><span class="line">      TProtocol inputProtocol = <span class="keyword">null</span>;</span><br><span class="line">      TProtocol outputProtocol = <span class="keyword">null</span>;</span><br><span class="line">      ServerContext connectionContext = <span class="keyword">null</span>;</span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">        client = serverTransport_.accept();</span><br><span class="line">        <span class="keyword">if</span> (client != <span class="keyword">null</span>) &#123;</span><br><span class="line">          processor = processorFactory_.getProcessor(client);</span><br><span class="line">          inputTransport = inputTransportFactory_.getTransport(client);</span><br><span class="line">          outputTransport = outputTransportFactory_.getTransport(client);</span><br><span class="line">          inputProtocol = inputProtocolFactory_.getProtocol(inputTransport);</span><br><span class="line">          outputProtocol = outputProtocolFactory_.getProtocol(outputTransport);</span><br><span class="line">          <span class="keyword">if</span> (eventHandler_ != <span class="keyword">null</span>) &#123;</span><br><span class="line">            connectionContext = eventHandler_.createContext(inputProtocol, outputProtocol);</span><br><span class="line">          &#125;</span><br><span class="line">          <span class="keyword">while</span> (<span class="keyword">true</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span>(!processor.process(inputProtocol, outputProtocol)) &#123;</span><br><span class="line">              <span class="keyword">break</span>;</span><br><span class="line">            &#125;</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125; <span class="keyword">catch</span> (Exception x) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!stopped_) &#123;</span><br><span class="line">          LOGGER.error(<span class="string">"Error occurred during processing of message."</span>, x);</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="comment">//省略部分代码</span></span><br><span class="line">      ......</span><br><span class="line">    &#125;</span><br><span class="line">    setServing(<span class="keyword">false</span>);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>　　TSimpleServer中最重要的代码则是while循环中的 client = serverTransport_.accept();，它会一直阻塞在此处，直到有客户端的连接（TServerTransport为TServerSocket，阻塞式IO实现）才返回。最后在同一个线程的while代码块中调用TProcessor.process方法。正常情况下，该逻辑导致serverTransport_.accept方法只会调用一次，即只能正常处理第一个客户端的连接和消息。如果process方法处理非常耗时，则会影响该客户端的后续消息请求，所以他只适合采用测试环境使用。</p>
<h2 id="TThreadPoolServer"><a href="#TThreadPoolServer" class="headerlink" title="TThreadPoolServer"></a>TThreadPoolServer</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TThreadPoolServer</span> <span class="keyword">extends</span> <span class="title">TServer</span> </span>&#123;</span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Args</span> <span class="keyword">extends</span> <span class="title">AbstractServerArgs</span>&lt;<span class="title">Args</span>&gt; </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> minWorkerThreads = <span class="number">5</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> maxWorkerThreads = Integer.MAX_VALUE;</span><br><span class="line">    <span class="comment">//其他属性省略</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">Args</span><span class="params">(TServerTransport transport)</span> </span>&#123;</span><br><span class="line">      <span class="keyword">super</span>(transport);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Args <span class="title">minWorkerThreads</span><span class="params">(<span class="keyword">int</span> n)</span> </span>&#123;</span><br><span class="line">      minWorkerThreads = n;</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//其他参数设置方法</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">//其他属性省略</span></span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="title">TThreadPoolServer</span><span class="params">(Args args)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">super</span>(args);</span><br><span class="line">    <span class="comment">//属性初始化省略</span></span><br><span class="line">    beBackoffSlotInMillis = args.beBackoffSlotLengthUnit.toMillis(args.beBackoffSlotLength);</span><br><span class="line"></span><br><span class="line">    executorService_ = args.executorService != <span class="keyword">null</span> ?</span><br><span class="line">        args.executorService : createDefaultExecutorService(args);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">//创建默认的线程池</span></span><br><span class="line">  <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> ExecutorService <span class="title">createDefaultExecutorService</span><span class="params">(Args args)</span> </span>&#123;</span><br><span class="line">    SynchronousQueue&lt;Runnable&gt; executorQueue =</span><br><span class="line">      <span class="keyword">new</span> SynchronousQueue&lt;Runnable&gt;();</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> ThreadPoolExecutor(args.minWorkerThreads,</span><br><span class="line">                                  args.maxWorkerThreads,</span><br><span class="line">                                  args.stopTimeoutVal,</span><br><span class="line">                                  TimeUnit.SECONDS,</span><br><span class="line">                                  executorQueue);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">serve</span><span class="params">()</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">int</span> failureCount = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">while</span> (!stopped_) &#123;</span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">        TTransport client = serverTransport_.accept();</span><br><span class="line">		<span class="comment">//将新的连接client放到WorkerProcess中，</span></span><br><span class="line">        WorkerProcess wp = <span class="keyword">new</span> WorkerProcess(client);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">int</span> retryCount = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">long</span> remainTimeInMillis = requestTimeoutUnit.toMillis(requestTimeout);</span><br><span class="line">        <span class="keyword">while</span>(<span class="keyword">true</span>) &#123;</span><br><span class="line">          <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">//放入线程池中执行</span></span><br><span class="line">            executorService_.execute(wp);</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">          &#125; <span class="keyword">catch</span>(Throwable t) &#123;</span><br><span class="line">            <span class="comment">//错误处理代码</span></span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125; <span class="keyword">catch</span> (TTransportException ttx) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!stopped_) &#123;</span><br><span class="line">          ++failureCount;</span><br><span class="line">          LOGGER.warn(<span class="string">"Transport error occurred during acceptance of message."</span>, ttx);</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">	<span class="comment">//处理线程池的关闭</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">//内部类，客户端新连接处理线程</span></span><br><span class="line">  <span class="keyword">private</span> <span class="class"><span class="keyword">class</span> <span class="title">WorkerProcess</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      TProcessor processor = <span class="keyword">null</span>;</span><br><span class="line">      TTransport inputTransport = <span class="keyword">null</span>;</span><br><span class="line">      TTransport outputTransport = <span class="keyword">null</span>;</span><br><span class="line">      TProtocol inputProtocol = <span class="keyword">null</span>;</span><br><span class="line">      TProtocol outputProtocol = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line">      TServerEventHandler eventHandler = <span class="keyword">null</span>;</span><br><span class="line">      ServerContext connectionContext = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">        processor = processorFactory_.getProcessor(client_);</span><br><span class="line">        inputTransport = inputTransportFactory_.getTransport(client_);</span><br><span class="line">        outputTransport = outputTransportFactory_.getTransport(client_);</span><br><span class="line">        inputProtocol = inputProtocolFactory_.getProtocol(inputTransport);</span><br><span class="line">        outputProtocol = outputProtocolFactory_.getProtocol(outputTransport);	  </span><br><span class="line"></span><br><span class="line">        <span class="keyword">while</span> (<span class="keyword">true</span>) &#123;</span><br><span class="line">			<span class="comment">//process处理异常，则推送while循环，结束该线程</span></span><br><span class="line">            <span class="keyword">if</span>(stopped_ || !processor.process(inputProtocol, outputProtocol)) &#123;</span><br><span class="line">              <span class="keyword">break</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125; <span class="keyword">catch</span> (Exception x) &#123;</span><br><span class="line">        LOGGER.error(<span class="string">"Error occurred during processing of message."</span>, x);</span><br><span class="line">      &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">        <span class="comment">//.........</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>　　从上面代码中我们可以看到，它与TSimpleServer相同的是：它的serve方法内部也存在一个while循环，代码client = serverTransport_.accept();会一直阻塞，直到有客户端的连接（TServerTransport为TServerSocket，阻塞式IO实现）才返回。而不同之处则在于：新连接到达后，新生成的Socket会封装到WorkerProcess（实现了Runnable接口），放到线程池中运行！其特性就是多个客户单端并发执行，但是在每个客户端的内部，则是按顺序处理每个请求。</p>
<h4 id="AbstractNonblockingServer"><a href="#AbstractNonblockingServer" class="headerlink" title="AbstractNonblockingServer"></a>AbstractNonblockingServer</h4><p>　　在讲解TNonblockingServer、THsHaServer和TThreadedSelectorServer之前，我们先看看AbstractNonblockingServer。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">AbstractNonblockingServer</span> <span class="keyword">extends</span> <span class="title">TServer</span> </span>&#123;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">AbstractNonblockingServerArgs</span>&lt;<span class="title">T</span> <span class="keyword">extends</span> <span class="title">AbstractNonblockingServerArgs</span>&lt;<span class="title">T</span>&gt;&gt; <span class="keyword">extends</span> <span class="title">AbstractServerArgs</span>&lt;<span class="title">T</span>&gt; </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">long</span> maxReadBufferBytes = Long.MAX_VALUE;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">AbstractNonblockingServerArgs</span><span class="params">(TNonblockingServerTransport transport)</span> </span>&#123;</span><br><span class="line">      <span class="keyword">super</span>(transport);</span><br><span class="line">      transportFactory(<span class="keyword">new</span> TFramedTransport.Factory());</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="title">AbstractNonblockingServer</span><span class="params">(AbstractNonblockingServerArgs args)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">super</span>(args);</span><br><span class="line">    MAX_READ_BUFFER_BYTES = args.maxReadBufferBytes;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">serve</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (!startThreads()) &#123;</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//其他非重要代码</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> <span class="keyword">abstract</span> <span class="keyword">boolean</span> <span class="title">startThreads</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> <span class="keyword">abstract</span> <span class="keyword">boolean</span> <span class="title">requestInvoke</span><span class="params">(FrameBuffer frameBuffer)</span></span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">protected</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">AbstractSelectThread</span> <span class="keyword">extends</span> <span class="title">Thread</span> </span>&#123;</span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">final</span> Selector selector;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">final</span> Set&lt;FrameBuffer&gt; selectInterestChanges = <span class="keyword">new</span> HashSet&lt;FrameBuffer&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">AbstractSelectThread</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">      <span class="keyword">this</span>.selector = SelectorProvider.provider().openSelector();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">wakeupSelector</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      selector.wakeup();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">requestSelectInterestChange</span><span class="params">(FrameBuffer frameBuffer)</span> </span>&#123;</span><br><span class="line">      <span class="keyword">synchronized</span> (selectInterestChanges) &#123;</span><br><span class="line">        selectInterestChanges.add(frameBuffer);</span><br><span class="line">      &#125;</span><br><span class="line">      selector.wakeup();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">processInterestChanges</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="keyword">synchronized</span> (selectInterestChanges) &#123;</span><br><span class="line">        <span class="keyword">for</span> (FrameBuffer fb : selectInterestChanges) &#123;</span><br><span class="line">          fb.changeSelectInterests();</span><br><span class="line">        &#125;</span><br><span class="line">        selectInterestChanges.clear();</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">handleRead</span><span class="params">(SelectionKey key)</span> </span>&#123;</span><br><span class="line">      FrameBuffer buffer = (FrameBuffer) key.attachment();</span><br><span class="line">      <span class="keyword">if</span> (!buffer.read()) &#123;</span><br><span class="line">        cleanupSelectionKey(key);</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="comment">// if the buffer's frame read is complete, invoke the method.</span></span><br><span class="line">      <span class="keyword">if</span> (buffer.isFrameFullyRead()) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!requestInvoke(buffer)) &#123;</span><br><span class="line">          cleanupSelectionKey(key);</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">	</span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">handleWrite</span><span class="params">(SelectionKey key)</span> </span>&#123;</span><br><span class="line">      FrameBuffer buffer = (FrameBuffer) key.attachment();</span><br><span class="line">      <span class="keyword">if</span> (!buffer.write()) &#123;</span><br><span class="line">        cleanupSelectionKey(key);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　我们可以看到，在AbstractNonblockingServer中，最重要的一个抽象方法为：startThreads，以及一个内部抽象类：AbstractSelectThread。在AbstractSelectThread的构造方法中，我们初始化了一个Selector。下面我们看看TNonblockingServer对startThreads方法和AbstractSelectThread的run方法的实现</p>
<h2 id="TNonblockingServer"><a href="#TNonblockingServer" class="headerlink" title="TNonblockingServer"></a>TNonblockingServer</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TNonblockingServer</span> <span class="keyword">extends</span> <span class="title">AbstractNonblockingServer</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">private</span> SelectAcceptThread selectAcceptThread_;</span><br><span class="line"></span><br><span class="line">  <span class="annotation">@Override</span></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> <span class="keyword">boolean</span> <span class="title">startThreads</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="comment">// start the selector</span></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      selectAcceptThread_ = <span class="keyword">new</span> SelectAcceptThread((TNonblockingServerTransport)serverTransport_);</span><br><span class="line">      selectAcceptThread_.start();</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">      LOGGER.error(<span class="string">"Failed to start selector thread!"</span>, e);</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="annotation">@Override</span></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">waitForShutdown</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    joinSelector();</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">joinSelector</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      selectAcceptThread_.join();</span><br><span class="line">    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;&#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="annotation">@Override</span></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> <span class="keyword">boolean</span> <span class="title">requestInvoke</span><span class="params">(FrameBuffer frameBuffer)</span> </span>&#123;</span><br><span class="line">    frameBuffer.invoke();</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">protected</span> <span class="class"><span class="keyword">class</span> <span class="title">SelectAcceptThread</span> <span class="keyword">extends</span> <span class="title">AbstractSelectThread</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> TNonblockingServerTransport serverTransport;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">SelectAcceptThread</span><span class="params">(<span class="keyword">final</span> TNonblockingServerTransport serverTransport)</span></span><br><span class="line">    <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">      <span class="keyword">this</span>.serverTransport = serverTransport;</span><br><span class="line">      serverTransport.registerSelector(selector);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (eventHandler_ != <span class="keyword">null</span>) &#123;</span><br><span class="line">          eventHandler_.preServe();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">while</span> (!stopped_) &#123;</span><br><span class="line">          select();</span><br><span class="line">          processInterestChanges();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">for</span> (SelectionKey selectionKey : selector.keys()) &#123;</span><br><span class="line">          cleanupSelectionKey(selectionKey);</span><br><span class="line">        &#125;</span><br><span class="line">      &#125; <span class="keyword">catch</span> (Throwable t) &#123;</span><br><span class="line">        LOGGER.error(<span class="string">"run() exiting due to uncaught error"</span>, t);</span><br><span class="line">      &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">          selector.close();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">          LOGGER.error(<span class="string">"Got an IOException while closing selector!"</span>, e);</span><br><span class="line">        &#125;</span><br><span class="line">        stopped_ = <span class="keyword">true</span>;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">select</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">        selector.select();</span><br><span class="line"></span><br><span class="line">        Iterator&lt;SelectionKey&gt; selectedKeys = selector.selectedKeys().iterator();</span><br><span class="line">        <span class="keyword">while</span> (!stopped_ &amp;&amp; selectedKeys.hasNext()) &#123;</span><br><span class="line">          SelectionKey key = selectedKeys.next();</span><br><span class="line">          selectedKeys.remove();</span><br><span class="line">          <span class="keyword">if</span> (!key.isValid()) &#123;</span><br><span class="line">            <span class="keyword">continue</span>;</span><br><span class="line">          &#125;</span><br><span class="line"></span><br><span class="line">          <span class="keyword">if</span> (key.isAcceptable()) &#123;</span><br><span class="line">            handleAccept();</span><br><span class="line">          &#125; <span class="keyword">else</span> <span class="keyword">if</span> (key.isReadable()) &#123;</span><br><span class="line">            handleRead(key);</span><br><span class="line">          &#125; <span class="keyword">else</span> <span class="keyword">if</span> (key.isWritable()) &#123;</span><br><span class="line">            handleWrite(key);</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">        LOGGER.warn(<span class="string">"Got an IOException while selecting!"</span>, e);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span><br><span class="line">     * Accept a new connection.</span><br><span class="line">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">handleAccept</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">      SelectionKey clientKey = <span class="keyword">null</span>;</span><br><span class="line">      TNonblockingTransport client = <span class="keyword">null</span>;</span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="comment">// accept the connection</span></span><br><span class="line">        client = (TNonblockingTransport)serverTransport.accept();</span><br><span class="line">        clientKey = client.registerSelector(selector, SelectionKey.OP_READ);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// add this key to the map</span></span><br><span class="line">          FrameBuffer frameBuffer = createFrameBuffer(client, clientKey, SelectAcceptThread.<span class="keyword">this</span>);</span><br><span class="line"></span><br><span class="line">          clientKey.attach(frameBuffer);</span><br><span class="line">      &#125; <span class="keyword">catch</span> (TTransportException tte) &#123;</span><br><span class="line">        <span class="comment">// something went wrong accepting.</span></span><br><span class="line">        LOGGER.warn(<span class="string">"Exception trying to accept!"</span>, tte);</span><br><span class="line">        tte.printStackTrace();</span><br><span class="line">        <span class="keyword">if</span> (clientKey != <span class="keyword">null</span>) cleanupSelectionKey(clientKey);</span><br><span class="line">        <span class="keyword">if</span> (client != <span class="keyword">null</span>) client.close();</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125; <span class="comment">// SelectAcceptThread</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>　　在startThreads方法中，生成了一个SelectAcceptThread对象，并调用了start方法，我们进入SelectAcceptThread的run方法，可以发现，其在一个线程中遍历SelectedKeys集合，根据interests，如acceptable、readable和writable则分别交由对应的方法处理，我们进入不同的方法及其调用的方法，可以发现都在同一个线程中运行（注意requestInvoke方法，下面会重点讲解）。这就印证了上面说的多个客户端的请求，实际上是通过一个线程（SelectAcceptThread）处理的，包括io读取和业务代码执行，很明显存在性能问题。</p>
<h2 id="THsHaServer"><a href="#THsHaServer" class="headerlink" title="THsHaServer"></a>THsHaServer</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">THsHaServer</span> <span class="keyword">extends</span> <span class="title">TNonblockingServer</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Args</span> <span class="keyword">extends</span> <span class="title">AbstractNonblockingServerArgs</span>&lt;<span class="title">Args</span>&gt; </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> minWorkerThreads = <span class="number">5</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> maxWorkerThreads = Integer.MAX_VALUE;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> stopTimeoutVal = <span class="number">60</span>;</span><br><span class="line">    <span class="keyword">private</span> TimeUnit stopTimeoutUnit = TimeUnit.SECONDS;</span><br><span class="line">    <span class="keyword">private</span> ExecutorService executorService = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">Args</span><span class="params">(TNonblockingServerTransport transport)</span> </span>&#123;</span><br><span class="line">      <span class="keyword">super</span>(transport);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//各种参数设置方法</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">final</span> ExecutorService invoker;</span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="title">THsHaServer</span><span class="params">(Args args)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">super</span>(args);</span><br><span class="line"></span><br><span class="line">    invoker = args.executorService == <span class="keyword">null</span> ? createInvokerPool(args) : args.executorService;</span><br><span class="line">    <span class="keyword">this</span>.args = args;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="annotation">@Override</span></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">waitForShutdown</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    joinSelector();</span><br><span class="line">    gracefullyShutdownInvokerPool();</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">//创建一个线程池</span></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> <span class="keyword">static</span> ExecutorService <span class="title">createInvokerPool</span><span class="params">(Args options)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">int</span> minWorkerThreads = options.minWorkerThreads;</span><br><span class="line">    <span class="keyword">int</span> maxWorkerThreads = options.maxWorkerThreads;</span><br><span class="line">    <span class="keyword">int</span> stopTimeoutVal = options.stopTimeoutVal;</span><br><span class="line">    TimeUnit stopTimeoutUnit = options.stopTimeoutUnit;</span><br><span class="line"></span><br><span class="line">    LinkedBlockingQueue&lt;Runnable&gt; queue = <span class="keyword">new</span> LinkedBlockingQueue&lt;Runnable&gt;();</span><br><span class="line">    ExecutorService invoker = <span class="keyword">new</span> ThreadPoolExecutor(minWorkerThreads,</span><br><span class="line">      maxWorkerThreads, stopTimeoutVal, stopTimeoutUnit, queue);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> invoker;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="annotation">@Override</span></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> <span class="keyword">boolean</span> <span class="title">requestInvoke</span><span class="params">(FrameBuffer frameBuffer)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      Runnable invocation = getRunnable(frameBuffer);</span><br><span class="line">      invoker.execute(invocation);</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (RejectedExecutionException rx) &#123;</span><br><span class="line">      LOGGER.warn(<span class="string">"ExecutorService rejected execution!"</span>, rx);</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> Runnable <span class="title">getRunnable</span><span class="params">(FrameBuffer frameBuffer)</span></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> Invocation(frameBuffer);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>　　我们可以看到THsHaServer继承自TNonblockingServer，既然如此，他也是在SelectAcceptThread线程中执行SelectionKey集合的遍历。但是其requestInvoke方法则与TNonblockingServer的不同。其将每次读取到的数据封装到一个Runnable中，交由线程池执行。所以THsHaServer是单个线程执行io读取，通过线程池执行业务代码。</p>
<h2 id="TThreadedSelectorServer"><a href="#TThreadedSelectorServer" class="headerlink" title="TThreadedSelectorServer"></a>TThreadedSelectorServer</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TThreadedSelectorServer</span> <span class="keyword">extends</span> <span class="title">AbstractNonblockingServer</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">private</span> AcceptThread acceptThread;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">final</span> Set&lt;SelectorThread&gt; selectorThreads = <span class="keyword">new</span> HashSet&lt;SelectorThread&gt;();</span><br><span class="line"></span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">final</span> ExecutorService invoker;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="title">TThreadedSelectorServer</span><span class="params">(Args args)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">super</span>(args);</span><br><span class="line">    args.validate();</span><br><span class="line">    invoker = args.executorService == <span class="keyword">null</span> ? createDefaultExecutor(args) : args.executorService;</span><br><span class="line">    <span class="keyword">this</span>.args = args;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="annotation">@Override</span></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> <span class="keyword">boolean</span> <span class="title">startThreads</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; args.selectorThreads; ++i) &#123;</span><br><span class="line">        selectorThreads.add(<span class="keyword">new</span> SelectorThread(args.acceptQueueSizePerThread));</span><br><span class="line">      &#125;</span><br><span class="line">      acceptThread = <span class="keyword">new</span> AcceptThread((TNonblockingServerTransport) serverTransport_,</span><br><span class="line">        createSelectorThreadLoadBalancer(selectorThreads));</span><br><span class="line">      <span class="comment">//启动SelectorThread和acceptThread线程</span></span><br><span class="line">      <span class="keyword">for</span> (SelectorThread thread : selectorThreads) &#123;</span><br><span class="line">        thread.start();</span><br><span class="line">      &#125;</span><br><span class="line">      acceptThread.start();</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (IOException e) &#123;&#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="annotation">@Override</span></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> <span class="keyword">boolean</span> <span class="title">requestInvoke</span><span class="params">(FrameBuffer frameBuffer)</span> </span>&#123;</span><br><span class="line">    Runnable invocation = getRunnable(frameBuffer);</span><br><span class="line">    <span class="keyword">if</span> (invoker != <span class="keyword">null</span>) &#123;</span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">        invoker.execute(invocation);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">      &#125; <span class="keyword">catch</span> (RejectedExecutionException rx) &#123;</span><br><span class="line">        LOGGER.warn(<span class="string">"ExecutorService rejected execution!"</span>, rx);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      <span class="comment">// Invoke on the caller's thread</span></span><br><span class="line">      invocation.run();</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> Runnable <span class="title">getRunnable</span><span class="params">(FrameBuffer frameBuffer)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> Invocation(frameBuffer);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> <span class="keyword">static</span> ExecutorService <span class="title">createDefaultExecutor</span><span class="params">(Args options)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> (options.workerThreads &gt; <span class="number">0</span>) ? Executors.newFixedThreadPool(options.workerThreads) : <span class="keyword">null</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> BlockingQueue&lt;TNonblockingTransport&gt; <span class="title">createDefaultAcceptQueue</span><span class="params">(<span class="keyword">int</span> queueSize)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> ArrayBlockingQueue&lt;TNonblockingTransport&gt;(queueSize);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">protected</span> <span class="class"><span class="keyword">class</span> <span class="title">AcceptThread</span> <span class="keyword">extends</span> <span class="title">Thread</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> TNonblockingServerTransport serverTransport;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Selector acceptSelector;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> SelectorThreadLoadBalancer threadChooser;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">AcceptThread</span><span class="params">(TNonblockingServerTransport serverTransport,</span><br><span class="line">        SelectorThreadLoadBalancer threadChooser)</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">      <span class="keyword">this</span>.serverTransport = serverTransport;</span><br><span class="line">      <span class="keyword">this</span>.threadChooser = threadChooser;</span><br><span class="line">      <span class="keyword">this</span>.acceptSelector = SelectorProvider.provider().openSelector();</span><br><span class="line">      <span class="keyword">this</span>.serverTransport.registerSelector(acceptSelector);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="keyword">while</span> (!stopped_) &#123;</span><br><span class="line">        select();</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">select</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">        acceptSelector.select();</span><br><span class="line">        Iterator&lt;SelectionKey&gt; selectedKeys = acceptSelector.selectedKeys().iterator();</span><br><span class="line">        <span class="keyword">while</span> (!stopped_ &amp;&amp; selectedKeys.hasNext()) &#123;</span><br><span class="line">          SelectionKey key = selectedKeys.next();</span><br><span class="line">          selectedKeys.remove();</span><br><span class="line"></span><br><span class="line">          <span class="keyword">if</span> (key.isAcceptable()) &#123;</span><br><span class="line">            handleAccept();</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125; <span class="keyword">catch</span> (IOException e) &#123;&#125;</span><br><span class="line">    &#125;</span><br><span class="line">	</span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">handleAccept</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="keyword">final</span> TNonblockingTransport client = doAccept();</span><br><span class="line">      <span class="keyword">if</span> (client != <span class="keyword">null</span>) &#123;</span><br><span class="line">        <span class="keyword">final</span> SelectorThread targetThread = threadChooser.nextThread();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (args.acceptPolicy == Args.AcceptPolicy.FAST_ACCEPT || invoker == <span class="keyword">null</span>) &#123;</span><br><span class="line">          doAddAccept(targetThread, client);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">          <span class="keyword">try</span> &#123;</span><br><span class="line">            invoker.submit(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">              <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                doAddAccept(targetThread, client);</span><br><span class="line">              &#125;</span><br><span class="line">            &#125;);</span><br><span class="line">          &#125; <span class="keyword">catch</span> (RejectedExecutionException rx) &#123;&#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> TNonblockingTransport <span class="title">doAccept</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="keyword">return</span> (TNonblockingTransport) serverTransport.accept();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">doAddAccept</span><span class="params">(SelectorThread thread, TNonblockingTransport client)</span> </span>&#123;</span><br><span class="line">      <span class="keyword">if</span> (!thread.addAcceptedConnection(client)) &#123;</span><br><span class="line">        client.close();</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125; <span class="comment">// AcceptThread</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">protected</span> <span class="class"><span class="keyword">class</span> <span class="title">SelectorThread</span> <span class="keyword">extends</span> <span class="title">AbstractSelectThread</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> BlockingQueue&lt;TNonblockingTransport&gt; acceptedQueue;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">SelectorThread</span><span class="params">(<span class="keyword">int</span> maxPendingAccepts)</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">      <span class="keyword">this</span>(createDefaultAcceptQueue(maxPendingAccepts));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">addAcceptedConnection</span><span class="params">(TNonblockingTransport accepted)</span> </span>&#123;</span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">        acceptedQueue.put(accepted);</span><br><span class="line">      &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">      &#125;</span><br><span class="line">      selector.wakeup();</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">	</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="keyword">while</span> (!stopped_) &#123;</span><br><span class="line">          <span class="comment">//内部循环调用SelectKeys</span></span><br><span class="line">          select();</span><br><span class="line">		  <span class="comment">//将新连接的SocketChannel注册到selector中，上面select()方法中的循环才有效果</span></span><br><span class="line">          processAcceptedConnections();</span><br><span class="line">          processInterestChanges();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">for</span> (SelectionKey selectionKey : selector.keys()) &#123;</span><br><span class="line">          cleanupSelectionKey(selectionKey);</span><br><span class="line">        &#125;</span><br><span class="line">      &#125; <span class="keyword">catch</span> (Throwable t) &#123;</span><br><span class="line">        LOGGER.error(<span class="string">"run() on SelectorThread exiting due to uncaught error"</span>, t);</span><br><span class="line">      &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">          selector.close();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">          LOGGER.error(<span class="string">"Got an IOException while closing selector!"</span>, e);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// This will wake up the accept thread and the other selector threads</span></span><br><span class="line">        TThreadedSelectorServer.<span class="keyword">this</span>.stop();</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">	</span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">select</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="comment">//此处本应该阻塞，但是每次新连接到来时，</span></span><br><span class="line">        <span class="comment">//都会调用addAcceptedConnection方法，它里面调用了wakeup方法，使其立即返回</span></span><br><span class="line">        selector.select();</span><br><span class="line"></span><br><span class="line">        Iterator&lt;SelectionKey&gt; selectedKeys = selector.selectedKeys().iterator();</span><br><span class="line">        <span class="keyword">while</span> (!stopped_ &amp;&amp; selectedKeys.hasNext()) &#123;</span><br><span class="line">          SelectionKey key = selectedKeys.next();</span><br><span class="line">          selectedKeys.remove();</span><br><span class="line"></span><br><span class="line">          <span class="keyword">if</span> (key.isReadable()) &#123;</span><br><span class="line">            handleRead(key);</span><br><span class="line">          &#125; <span class="keyword">else</span> <span class="keyword">if</span> (key.isWritable()) &#123;</span><br><span class="line">            handleWrite(key);</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125; <span class="keyword">catch</span> (IOException e) &#123;&#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">processAcceptedConnections</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="keyword">while</span> (!stopped_) &#123;</span><br><span class="line">        TNonblockingTransport accepted = acceptedQueue.poll();</span><br><span class="line">        <span class="keyword">if</span> (accepted == <span class="keyword">null</span>) &#123;</span><br><span class="line">          <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        registerAccepted(accepted);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">registerAccepted</span><span class="params">(TNonblockingTransport accepted)</span> </span>&#123;</span><br><span class="line">      SelectionKey clientKey = <span class="keyword">null</span>;</span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">        clientKey = accepted.registerSelector(selector, SelectionKey.OP_READ);</span><br><span class="line"></span><br><span class="line">        FrameBuffer frameBuffer = createFrameBuffer(accepted, clientKey, SelectorThread.<span class="keyword">this</span>);</span><br><span class="line"></span><br><span class="line">        clientKey.attach(frameBuffer);</span><br><span class="line">      &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">        LOGGER.warn(<span class="string">"Failed to register accepted connection to selector!"</span>, e);</span><br><span class="line">        <span class="keyword">if</span> (clientKey != <span class="keyword">null</span>) &#123;</span><br><span class="line">          cleanupSelectionKey(clientKey);</span><br><span class="line">        &#125;</span><br><span class="line">        accepted.close();</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125; <span class="comment">// SelectorThread</span></span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> SelectorThreadLoadBalancer <span class="title">createSelectorThreadLoadBalancer</span><span class="params">(Collection&lt;? extends SelectorThread&gt; threads)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> SelectorThreadLoadBalancer(threads);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">//round robin 负载均衡，好诡异的写法</span></span><br><span class="line">  <span class="keyword">protected</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">SelectorThreadLoadBalancer</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Collection&lt;? extends SelectorThread&gt; threads;</span><br><span class="line">    <span class="keyword">private</span> Iterator&lt;? extends SelectorThread&gt; nextThreadIterator;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> &lt;T extends SelectorThread&gt; SelectorThreadLoadBalancer(Collection&lt;T&gt; threads) &#123;</span><br><span class="line">      <span class="keyword">if</span> (threads.isEmpty()) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">"At least one selector thread is required"</span>);</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">this</span>.threads = Collections.unmodifiableList(<span class="keyword">new</span> ArrayList&lt;T&gt;(threads));</span><br><span class="line">      nextThreadIterator = <span class="keyword">this</span>.threads.iterator();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> SelectorThread <span class="title">nextThread</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="keyword">if</span> (!nextThreadIterator.hasNext()) &#123;</span><br><span class="line">        nextThreadIterator = threads.iterator();</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">return</span> nextThreadIterator.next();</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>　　在TThreadedSelectorServer中，定义了两个内部类AcceptThread和SelectorThread。其中AcceptThread用于监听客户端的连接，在其handleAccept方法中，获取到一个TNonblockingTransport（封装了SocketChannel）。<br>　　通过SelectorThreadLoadBalancer的round robin 负载均衡策略，选取一个SelectorThread，并将上面生成TNonblockingTransport放到SelectorThread的阻塞队列中，同时调用Selector的wakeup方法，使其run方法中的processAcceptedConnections能被执行到，最后调用了registerAccepted，将每个连接的SocketChannel都注册到Selector中。<br>　　最后，我们可以看到TThreadedSelectorServer通过两个SelectorThread线程的负载，实现io的读写，而业务代码则由createDefaultExecutor方法生成的线程池执行。</p>
<h2 id="u603B_u7ED3"><a href="#u603B_u7ED3" class="headerlink" title="总结"></a>总结</h2><p>　　根据上面几种不同的实现，我们简单做如下总结：<br>　　thread-per-connection：即每个客户端连接对于一个专属的工作线程，工作线程等待客户端发送数据、接收处理数据、返回响应数据然后继续等待新的数据的到来，这种实际可以参考thrift的TThreadPoolServer的实现。但是这种模型不适合高并发的情况。<br>　　thread-on-event：工作线程独立于客户端连接，只用来处理特定的事件，例如当有数据到来时（data received event），工作线程在应用级别处理这些数据。这种模型需要nio使用非阻塞的方式，同时需要事件监测机制。这种模型被称为消息驱动模型（Reactor Pattern），该模型我们可以参考xSocket。Dispatcher维护一个Selector，客户端连接注册到Selector，当有数据可读可写时，Dispatcher触发响应的事件。</p>
<h2 id="u53C2_u8003_u8D44_u6599"><a href="#u53C2_u8003_u8D44_u6599" class="headerlink" title="参考资料"></a>参考资料</h2><p><a href="http://blog.csdn.net/whycold/article/details/8535932" target="_blank" rel="external">http://blog.csdn.net/whycold/article/details/8535932</a><br><a href="http://blog.csdn.net/azhao_dn/article/details/8898610" target="_blank" rel="external">http://blog.csdn.net/azhao_dn/article/details/8898610</a><br><a href="http://blog.csdn.net/azhao_dn/article/details/8899486" target="_blank" rel="external">http://blog.csdn.net/azhao_dn/article/details/8899486</a></p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2015/12/01/rpc/8.RPC系列之Thrift TServer源码分析/" data-id="cijzzpv2u001x1cfsgly5i1wp" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/java/">java</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/rpc/">rpc</a></li></ul>

    </footer>
  </div>
  
    
<nav id="article-nav">
  
    <a href="/2015/12/01/rpc/9.RPC系列之Thrift TProcessor源码分析/" id="article-nav-newer" class="article-nav-link-wrap">
      <strong class="article-nav-caption">Newer</strong>
      <div class="article-nav-title">
        
          RPC系列九之Thrift TProcessor源码分析
        
      </div>
    </a>
  
  
    <a href="/2015/12/01/rpc/7.RPC系列之Thrift TProtocol源码分析/" id="article-nav-older" class="article-nav-link-wrap">
      <strong class="article-nav-caption">Older</strong>
      <div class="article-nav-title">RPC系列七之Thrift TProtocol源码分析</div>
    </a>
  
</nav>

  
</article>

</section>
        
          <aside id="sidebar">
  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Categories</h3>
    <div class="widget">
      <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/cache/">cache</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/database/">database</a><span class="category-list-count">13</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/docker/">docker</a><span class="category-list-count">6</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/gis/">gis</a><span class="category-list-count">4</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/git/">git</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/go/">go</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/gradle/">gradle</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/groovy/">groovy</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/hadoop/">hadoop</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/java/">java</a><span class="category-list-count">18</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/linux/">linux</a><span class="category-list-count">4</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/log/">log</a><span class="category-list-count">11</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/mongodb/">mongodb</a><span class="category-list-count">14</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/mq/">mq</a><span class="category-list-count">6</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/mybatis/">mybatis</a><span class="category-list-count">9</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/netty/">netty</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/nginx/">nginx</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/nio/">nio</a><span class="category-list-count">19</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/nodejs/">nodejs</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/redis/">redis</a><span class="category-list-count">6</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/rpc/">rpc</a><span class="category-list-count">14</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/spring/">spring</a><span class="category-list-count">5</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/tomcat/">tomcat</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/zookeeper/">zookeeper</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/杂项/">杂项</a><span class="category-list-count">2</span></li></ul>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Tags</h3>
    <div class="widget">
      <ul class="tag-list"><li class="tag-list-item"><a class="tag-list-link" href="/tags/aop/">aop</a><span class="tag-list-count">8</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/aspectj/">aspectj</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/cache/">cache</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/classloader/">classloader</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/common-loggings/">common-loggings</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/commonjs/">commonjs</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/database/">database</a><span class="tag-list-count">10</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/docker/">docker</a><span class="tag-list-count">6</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/dubbo/">dubbo</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/fastdfs/">fastdfs</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/gclib/">gclib</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/geohash/">geohash</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/gis/">gis</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/git/">git</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/go/">go</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/gradle/">gradle</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/groovy/">groovy</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/hadoop/">hadoop</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/hessisan/">hessisan</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/java/">java</a><span class="tag-list-count">48</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/javassist/">javassist</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/kafka/">kafka</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/linux/">linux</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/log/">log</a><span class="tag-list-count">11</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/log4j/">log4j</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/logback/">logback</a><span class="tag-list-count">5</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/map/">map</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/memecached/">memecached</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mina/">mina</a><span class="tag-list-count">5</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mongodb/">mongodb</a><span class="tag-list-count">14</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mq/">mq</a><span class="tag-list-count">6</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mqtt/">mqtt</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mybatis/">mybatis</a><span class="tag-list-count">9</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/netty/">netty</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/nginx/">nginx</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/nio/">nio</a><span class="tag-list-count">5</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/nodejs/">nodejs</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/postgresql/">postgresql</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/protobuf/">protobuf</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/proxy/">proxy</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/push/">push</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/rabbitmq/">rabbitmq</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/redis/">redis</a><span class="tag-list-count">6</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/rpc/">rpc</a><span class="tag-list-count">14</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/sitemesh/">sitemesh</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/sld/">sld</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/slf4j/">slf4j</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/socket/">socket</a><span class="tag-list-count">7</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/spatialite-for-android/">spatialite for android</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/spi/">spi</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/spring/">spring</a><span class="tag-list-count">13</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/tomcat/">tomcat</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/transaction/">transaction</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/web/">web</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/xSocket/">xSocket</a><span class="tag-list-count">7</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/zbus/">zbus</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/zookeeper/">zookeeper</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/数据结构/">数据结构</a><span class="tag-list-count">2</span></li></ul>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Tag Cloud</h3>
    <div class="widget tagcloud">
      <a href="/tags/aop/" style="font-size: 15.38px;">aop</a> <a href="/tags/aspectj/" style="font-size: 11.54px;">aspectj</a> <a href="/tags/cache/" style="font-size: 11.54px;">cache</a> <a href="/tags/classloader/" style="font-size: 10px;">classloader</a> <a href="/tags/common-loggings/" style="font-size: 10px;">common-loggings</a> <a href="/tags/commonjs/" style="font-size: 12.31px;">commonjs</a> <a href="/tags/database/" style="font-size: 16.92px;">database</a> <a href="/tags/docker/" style="font-size: 13.85px;">docker</a> <a href="/tags/dubbo/" style="font-size: 10px;">dubbo</a> <a href="/tags/fastdfs/" style="font-size: 10px;">fastdfs</a> <a href="/tags/gclib/" style="font-size: 10.77px;">gclib</a> <a href="/tags/geohash/" style="font-size: 10px;">geohash</a> <a href="/tags/gis/" style="font-size: 10px;">gis</a> <a href="/tags/git/" style="font-size: 10.77px;">git</a> <a href="/tags/go/" style="font-size: 10px;">go</a> <a href="/tags/gradle/" style="font-size: 10px;">gradle</a> <a href="/tags/groovy/" style="font-size: 10px;">groovy</a> <a href="/tags/hadoop/" style="font-size: 10px;">hadoop</a> <a href="/tags/hessisan/" style="font-size: 11.54px;">hessisan</a> <a href="/tags/java/" style="font-size: 20px;">java</a> <a href="/tags/javassist/" style="font-size: 10px;">javassist</a> <a href="/tags/kafka/" style="font-size: 11.54px;">kafka</a> <a href="/tags/linux/" style="font-size: 12.31px;">linux</a> <a href="/tags/log/" style="font-size: 17.69px;">log</a> <a href="/tags/log4j/" style="font-size: 12.31px;">log4j</a> <a href="/tags/logback/" style="font-size: 13.08px;">logback</a> <a href="/tags/map/" style="font-size: 10px;">map</a> <a href="/tags/memecached/" style="font-size: 10.77px;">memecached</a> <a href="/tags/mina/" style="font-size: 13.08px;">mina</a> <a href="/tags/mongodb/" style="font-size: 19.23px;">mongodb</a> <a href="/tags/mq/" style="font-size: 13.85px;">mq</a> <a href="/tags/mqtt/" style="font-size: 10.77px;">mqtt</a> <a href="/tags/mybatis/" style="font-size: 16.15px;">mybatis</a> <a href="/tags/netty/" style="font-size: 10px;">netty</a> <a href="/tags/nginx/" style="font-size: 11.54px;">nginx</a> <a href="/tags/nio/" style="font-size: 13.08px;">nio</a> <a href="/tags/nodejs/" style="font-size: 10px;">nodejs</a> <a href="/tags/postgresql/" style="font-size: 10.77px;">postgresql</a> <a href="/tags/protobuf/" style="font-size: 10px;">protobuf</a> <a href="/tags/proxy/" style="font-size: 10px;">proxy</a> <a href="/tags/push/" style="font-size: 10px;">push</a> <a href="/tags/rabbitmq/" style="font-size: 11.54px;">rabbitmq</a> <a href="/tags/redis/" style="font-size: 13.85px;">redis</a> <a href="/tags/rpc/" style="font-size: 19.23px;">rpc</a> <a href="/tags/sitemesh/" style="font-size: 10px;">sitemesh</a> <a href="/tags/sld/" style="font-size: 10px;">sld</a> <a href="/tags/slf4j/" style="font-size: 10px;">slf4j</a> <a href="/tags/socket/" style="font-size: 14.62px;">socket</a> <a href="/tags/spatialite-for-android/" style="font-size: 10px;">spatialite for android</a> <a href="/tags/spi/" style="font-size: 10px;">spi</a> <a href="/tags/spring/" style="font-size: 18.46px;">spring</a> <a href="/tags/tomcat/" style="font-size: 10.77px;">tomcat</a> <a href="/tags/transaction/" style="font-size: 10px;">transaction</a> <a href="/tags/web/" style="font-size: 10px;">web</a> <a href="/tags/xSocket/" style="font-size: 14.62px;">xSocket</a> <a href="/tags/zbus/" style="font-size: 10px;">zbus</a> <a href="/tags/zookeeper/" style="font-size: 10.77px;">zookeeper</a> <a href="/tags/数据结构/" style="font-size: 10.77px;">数据结构</a>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Archives</h3>
    <div class="widget">
      <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2016/01/">January 2016</a><span class="archive-list-count">67</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/12/">December 2015</a><span class="archive-list-count">81</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/11/">November 2015</a><span class="archive-list-count">2</span></li></ul>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Recents</h3>
    <div class="widget">
      <ul>
        
          <li>
            <a href="/2016/01/30/资料/">(no title)</a>
          </li>
        
          <li>
            <a href="/2016/01/30/java/13.Classloader系列一/">ClassLoader系列一</a>
          </li>
        
          <li>
            <a href="/2016/01/29/hadoop/1.hadoop系列之源码编译/">hadoop系列一之源码编译</a>
          </li>
        
          <li>
            <a href="/2016/01/29/go/1.GO系列之入门/">Go系列一之入门</a>
          </li>
        
          <li>
            <a href="/2016/01/28/tomcat/2.tomcat性能优化/">tomcat性能优化</a>
          </li>
        
      </ul>
    </div>
  </div>

  
</aside>
        
      </div>
      <footer id="footer">
  
  <div class="outer">
    <div id="footer-info" class="inner">
      &copy; 2016 John Doe<br>
      Powered by <a href="http://hexo.io/" target="_blank">Hexo</a>
    </div>
  </div>
</footer>
    </div>
    <nav id="mobile-nav">
  
    <a href="/" class="mobile-nav-link">Home</a>
  
    <a href="/archives" class="mobile-nav-link">Archives</a>
  
</nav>
    


<script src="http://libs.baidu.com/jquery/2.0.3/jquery.min.js"></script>


  <link rel="stylesheet" href="/fancybox/jquery.fancybox.css" type="text/css">
  <script src="/fancybox/jquery.fancybox.pack.js" type="text/javascript"></script>


<script src="/js/script.js" type="text/javascript"></script>

  </div>
</body>
</html>